//
//      $Id$
//
//	x_ovfl.sa 3.5 7/1/91
//
//	fpsp_ovfl --- FPSP handler for overflow exception
//
//	Overflow occurs when a floating-point intermediate result is
//	too large to be represented in a floating-point data register,
//	or when storing to memory, the contents of a floating-point
//	data register are too large to be represented in the
//	destination format.
//		
// Trap disabled results
//
// If the instruction is move_out, then garbage is stored in the
// destination.  If the instruction is not move_out, then the
// destination is not affected.  For 68881 compatibility, the
// following values should be stored at the destination, based
// on the current rounding mode:
//
//  RN	Infinity with the sign of the intermediate result.
//  RZ	Largest magnitude number, with the sign of the
//	intermediate result.
//  RM   For pos overflow, the largest pos number. For neg overflow,
//	-infinity
//  RP   For pos overflow, +infinity. For neg overflow, the largest
//	neg number
//
// Trap enabled results
// All trap disabled code applies.  In addition the exceptional
// operand needs to be made available to the users exception handler
// with a bias of $6000 subtracted from the exponent.
//
//

//		Copyright (C) Motorola, Inc. 1990
//			All Rights Reserved
//
//	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA 
//	The copyright notice above does not evidence any  
//	actual or intended publication of such source code.

X_OVFL:	//idnt    2,1 | Motorola 040 Floating Point Software Package

	|section	8

#include "fpsp.defs"

	|xref	ovf_r_x2
	|xref	ovf_r_x3
	|xref	store
	|xref	real_ovfl
	|xref	real_inex
	|xref	fpsp_done
	|xref	g_opcls
	|xref	b1238_fix

	.global	fpsp_ovfl
fpsp_ovfl:
	link		%a6,#-LOCAL_SIZE
	fsave		-(%a7)
	moveml		%d0-%d1/%a0-%a1,USER_DA(%a6)
	fmovemx	%fp0-%fp3,USER_FP0(%a6)
	fmoveml	%fpcr/%fpsr/%fpiar,USER_FPCR(%a6)

//
//	The 040 doesn't set the AINEX bit in the FPSR, the following
//	line temporarily rectifies this error.
//
	bsetb	#ainex_bit,FPSR_AEXCEPT(%a6)
//
	bsrl	ovf_adj		//denormalize, round & store interm op
//
//	if overflow traps not enabled check for inexact exception
//
	btstb	#ovfl_bit,FPCR_ENABLE(%a6)
	beqs	ck_inex	
//
	btstb		#E3,E_BYTE(%a6)
	beqs		no_e3_1
	bfextu		CMDREG3B(%a6){#6:#3},%d0	//get dest reg no
	bclrb		%d0,FPR_DIRTY_BITS(%a6)	//clr dest dirty bit
	bsrl		b1238_fix
	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
	orl		#sx_mask,E_BYTE(%a6)
no_e3_1:
	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
	fmovemx	USER_FP0(%a6),%fp0-%fp3
	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
	frestore	(%a7)+
	unlk		%a6
	bral		real_ovfl
//
// It is possible to have either inex2 or inex1 exceptions with the
// ovfl.  If the inex enable bit is set in the FPCR, and either
// inex2 or inex1 occurred, we must clean up and branch to the
// real inex handler.
//
ck_inex:
//	move.b		FPCR_ENABLE(%a6),%d0
//	and.b		FPSR_EXCEPT(%a6),%d0
//	andi.b		#$3,%d0
	btstb		#inex2_bit,FPCR_ENABLE(%a6)
	beqs		ovfl_exit
//
// Inexact enabled and reported, and we must take an inexact exception.
//
take_inex:
	btstb		#E3,E_BYTE(%a6)
	beqs		no_e3_2
	bfextu		CMDREG3B(%a6){#6:#3},%d0	//get dest reg no
	bclrb		%d0,FPR_DIRTY_BITS(%a6)	//clr dest dirty bit
	bsrl		b1238_fix
	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
	orl		#sx_mask,E_BYTE(%a6)
no_e3_2:
	moveb		#INEX_VEC,EXC_VEC+1(%a6)
	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
	fmovemx	USER_FP0(%a6),%fp0-%fp3
	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
	frestore	(%a7)+
	unlk		%a6
	bral		real_inex
	
ovfl_exit:
	bclrb	#E3,E_BYTE(%a6)	//test and clear E3 bit
	beqs	e1_set
//
// Clear dirty bit on dest resister in the frame before branching
// to b1238_fix.
//
	bfextu		CMDREG3B(%a6){#6:#3},%d0	//get dest reg no
	bclrb		%d0,FPR_DIRTY_BITS(%a6)	//clr dest dirty bit
	bsrl		b1238_fix		//test for bug1238 case

	movel		USER_FPSR(%a6),FPSR_SHADOW(%a6)
	orl		#sx_mask,E_BYTE(%a6)
	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
	fmovemx	USER_FP0(%a6),%fp0-%fp3
	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
	frestore	(%a7)+
	unlk		%a6
	bral		fpsp_done
e1_set:
	moveml		USER_DA(%a6),%d0-%d1/%a0-%a1
	fmovemx	USER_FP0(%a6),%fp0-%fp3
	fmoveml	USER_FPCR(%a6),%fpcr/%fpsr/%fpiar
	unlk		%a6
	bral		fpsp_done

//
//	ovf_adj
//
ovf_adj:
//
// Have a0 point to the correct operand. 
//
	btstb	#E3,E_BYTE(%a6)	//test E3 bit
	beqs	ovf_e1

	lea	WBTEMP(%a6),%a0
	bras	ovf_com
ovf_e1:
	lea	ETEMP(%a6),%a0

ovf_com:
	bclrb	#sign_bit,LOCAL_EX(%a0)
	sne	LOCAL_SGN(%a0)

	bsrl	g_opcls		//returns opclass in d0
	cmpiw	#3,%d0		//check for opclass3
	bnes	not_opc011

//
// FPSR_CC is saved and restored because ovf_r_x3 affects it. The
// CCs are defined to be 'not affected' for the opclass3 instruction.
//
	moveb	FPSR_CC(%a6),L_SCR1(%a6)
 	bsrl	ovf_r_x3	//returns a0 pointing to result
	moveb	L_SCR1(%a6),FPSR_CC(%a6)
	bral	store		//stores to memory or register
	
not_opc011:
	bsrl	ovf_r_x2	//returns a0 pointing to result
	bral	store		//stores to memory or register

	|end
